package arkham.data;

import java.util.*;

import arkham.data.Globals.MonsterAttribute;
import arkham.jaxb.ancientone.*;
import arkham.util.AHLogger;

/**
 * This class represents an Ancient One.
 * Apart from data that the Ancient One begins with, there is generally
 * not much additional info that needs to be tracked.
 * @author ctheng
 *
 */
public class AncientOne implements NamedEntity
{
	private static final int NEGATIVE_X_COMBAT_MODIFIER = -999;
	private String name;
	private String powerTitle;
	private String powerDesc;
	private String worshipperDesc;
	private String attackDesc;
	private String startOfBattleDesc;
	private int combatModifier;
	private int doomTrack;
	private List<MonsterAttribute> defenses;
	private List<WorshipperModifier> worshipperMods;
	private List<AncientOnePower> powers;
	/* In game state */
	private int doomTokens;
	private List<String> effects;
	
	
	public AncientOne(String name)
	{
		this.name = name;
		defenses = new ArrayList<MonsterAttribute>();
		effects = new ArrayList<String>();
		worshipperMods = new ArrayList<WorshipperModifier>();
		powers = new ArrayList<AncientOnePower>();
	}
	
	/**
	 * This method is called after the ancient one is selected.
	 */
	public void init()
	{
		doomTokens = 0;
		effects.clear();
	}
	
	/**
	 * Get the Ancient One's name
	 * @return the investigator's name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Gets the title of the Ancient One's power
	 * @return the power title
	 */
	public String getPowerTitle() {
		return powerTitle;
	}

	/**
	 * Gets the description of the Ancient One's power
	 * @return the description of the power
	 */
	public String getPowerDesc() {
		return powerDesc;
	}

	/**
	 * Get the description of the Ancient One's effect on worshippers
	 * @return the worshippers description
	 */
	public String getWorshipperDesc() {
		return worshipperDesc;
	}

	/**
	 * Get the description of the Ancient One's attack
	 * @return the attack description
	 */
	public String getAttackDesc() {
		return attackDesc;
	}

	/**
	 * Gets the start of battle description
	 * @return the start of battle description
	 */
	public String getStartOfBattleDesc() {
		return startOfBattleDesc;
	}

	/**
	 * Gets the Ancient One's combat modifier
	 * @return the combatModifier
	 */
	public int getCombatModifier() {
		return combatModifier;
	}

	/**
	 * Gets the length of the doom track
	 * @return the doom track
	 */
	public int getDoomTrack() {
		return doomTrack;
	}

	/**
	 * Gets a list of defensive attributes, ie. immunities and resistances
	 * @return the defenses of the Ancient One
	 */
	public List<MonsterAttribute> getDefenses() {
		return defenses;
	}

	/**
	 * Gets the number of doom tokens on the doom track
	 * @return the number of doom tokens
	 */
	public int getDoomTokens() {
		return doomTokens;
	}
	
	/**
	 * Modifies the number of doom tokens
	 * @param val the amount to modify by
	 */
	public void modifyDoomTokens(int val)
	{
		doomTokens += val;
	}
	
	/**
	 * Gets any effects present on the Ancient One
	 * @return the effects present
	 */
	public List<String> getEffects() {
		return effects;
	}
	
	/**
	 * Gets the list of modifiers to worshippers
	 * @return the list of modifiers
	 */
	public List<WorshipperModifier> getWorshipperModifiers()
	{
		return worshipperMods;
	}
	
	/**
	 * Gets the list of Ancient One powers
	 * @return the list of powers
	 */
	public List<AncientOnePower> getPowers()
	{
		return powers;
	}
	
	@Override
	public String toString()
	{
		return name;
	}
	
	/**
	 * This class describes a modification to a class of monsters
	 * caused by them worshipping the Ancient One
	 * @author ctheng
	 *
	 */
	public static class WorshipperModifier
	{
		private String monster;
		private List<String> effects;
		
		public WorshipperModifier()
		{
			effects = new ArrayList<String>();
		}

		/**
		 * @return the monster
		 */
		public String getMonster() {
			return monster;
		}

		/**
		 * @param monster the monster to set
		 */
		public void setMonster(String monster) {
			this.monster = monster;
		}

		/**
		 * @return the effect
		 */
		public List<String> getEffect() {
			return effects;
		}

		/**
		 * @param effect the effect to set
		 */
		public void addEffect(String effect) {
			effects.add(effect);
		}
		
		
	}
	
	/**
	 * This class describes a power that an Ancient One possesses.
	 * @author ctheng
	 *
	 */
	public static class AncientOnePower
	{

		private String phase;
		private String effect;
		
		public AncientOnePower()
		{
			
		}
		
		/**
		 * @return the phase
		 */
		public String getPhase() {
			return phase;
		}

		/**
		 * @param phase the phase to set
		 */
		public void setPhase(String phase) {
			this.phase = phase;
		}

		/**
		 * @return the effect
		 */
		public String getEffect() {
			return effect;
		}

		/**
		 * @param effect the effect to set
		 */
		public void setEffect(String effect) {
			this.effect = effect;
		}

	}
	
	public static AncientOne createAncientOneFromXml(AncientOneType xmlao)
	{
		AncientOne ao = new AncientOne(xmlao.getName());
		ao.powerTitle = xmlao.getPowerTitle();
		ao.powerDesc = xmlao.getPowerDescription();
		ao.worshipperDesc = xmlao.getWorshippersDescription();
		ao.attackDesc = xmlao.getAttackDescription();
		ao.startOfBattleDesc = xmlao.getStartOfBattlePower();
		/* Initialize combat modifier */
		String combatmod = xmlao.getCombatModifier();
		if (combatmod.equalsIgnoreCase("-X"))
		{
			ao.combatModifier = NEGATIVE_X_COMBAT_MODIFIER;
		}
		else
		{
			try
			{
				ao.combatModifier = Integer.parseInt(combatmod);
			}
			catch (NumberFormatException e)
			{
				AHLogger.error(ao.name + " has an invalid combat modifier: " + combatmod);
				return null;
			}
		}
		if (ao.combatModifier > 0)
		{
			AHLogger.error(ao.name + " must have a negative combat modifier! (too easy)");
		}
		ao.doomTrack = xmlao.getDoomTrack();
		/* Initialize list of defenses */
		for (String s : xmlao.getDefense())
		{
			if (!MonsterAttribute.isValidAttribute(s))
			{
				AHLogger.error(ao.name + " has an invalid defense : " + s);
				return null;
			}
			MonsterAttribute defense = MonsterAttribute.getAttribute(s);
			switch (defense)
			{
			case PHYS_RES:
			case PHYS_IMM:
			case MAG_RES:
			case MAG_IMM:
				ao.defenses.add(defense);
				break;
			default:
				AHLogger.error("The Ancient One " + ao.name + 
						" may not possess the attribute " + defense.toString());
				return null;
			}
		}
		/* Initialize worshipper powers */
		for (WorshipperModType wmtype : xmlao.getWorshipperMod())
		{
			WorshipperModifier wm = new WorshipperModifier();
			wm.setMonster(wmtype.getMonster());
			for (String power : wmtype.getPower())
			{
				wm.addEffect(power);
			}
		}
		
		for (AOPowerType aopower : xmlao.getPower())
		{
			AncientOnePower aop = new AncientOnePower();
			aop.setPhase(aopower.getPhase());
			aop.setEffect(aopower.getEffect().toString());
		}
		return ao;
	}
}
